package com.base.vistter.iframe.security.filter;

import com.alibaba.fastjson2.JSON;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.base.vistter.iframe.bean.Result;
import com.base.vistter.iframe.bean.SystemContextHolder;
import com.base.vistter.iframe.constant.CommonConstant;
import com.base.vistter.iframe.constant.UserConstant;
import com.base.vistter.iframe.menu.ErrorLoginEnum;
import com.base.vistter.iframe.model.LoginUserModel;
import com.base.vistter.iframe.properties.IframeProperties;
import com.base.vistter.iframe.utils.JwtUtils;
import com.base.vistter.iframe.utils.RedisUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import java.io.IOException;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;

@Slf4j
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {

    private IframeProperties iframeProperties;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, IframeProperties iframeProperties) {
        super(authenticationManager);
        this.iframeProperties = iframeProperties;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        String authorization = request.getHeader(CommonConstant.AUTHORIZATION);
        if (StringUtils.isEmpty(authorization) || !authorization.startsWith(CommonConstant.BEARER)) {
            filterChain.doFilter(request, response);
            return;
        }
        //删除bearer前缀
        authorization = authorization.replace(CommonConstant.BEARER + " ", "");

        String token = RedisUtils.getToken(authorization);
        if (StringUtils.isEmpty(token)) {
            filterChain.doFilter(request, response);
            return;
        }
        DecodedJWT decodedJWT = null;
        try {
            decodedJWT = JwtUtils.verifyToken(token, iframeProperties.getSignatureSecret());
        } catch (TokenExpiredException e) {
            response.setContentType("application/json;charset=UTF-8");
            Result<String> result = Result.error(ErrorLoginEnum.USER_LOGIN_TIMEOUT);
            response.getWriter().println(JSON.toJSONString(result));
            log.error(e.getMessage());
        }

        assert decodedJWT != null;
        int userId = JwtUtils.claimToInt(decodedJWT, UserConstant.USER_ID);
        String username = JwtUtils.claimToString(decodedJWT, UserConstant.USERNAME);
        int departId = JwtUtils.claimToInt(decodedJWT, UserConstant.DEPART_ID);
        int firmId = JwtUtils.claimToInt(decodedJWT, UserConstant.FIRM_ID);
        int roleId = JwtUtils.claimToInt(decodedJWT, UserConstant.ROLE_ID);
        int isAdmin = JwtUtils.claimToInt(decodedJWT, UserConstant.IS_ADMIN);

        LoginUserModel loginUserModel = new LoginUserModel(userId, username, departId, firmId, roleId, isAdmin);
        //即将超时的token自动刷新
        if ((JwtUtils.getExpiresDate(token).getTime() - iframeProperties.getTokenTime() * 60000) <= Calendar.getInstance().getTimeInMillis()) {
            String newToken = JwtUtils.createToken(loginUserModel, iframeProperties.getSignatureSecret());
            RedisUtils.setNewToken(token, newToken, iframeProperties.getTimeout(), TimeUnit.MINUTES);
        }
        //放入线程内
        SystemContextHolder.setSessionContext(loginUserModel);
        SystemContextHolder.setToken(authorization);

        Authentication authentication = new UsernamePasswordAuthenticationToken(username, null, null);
        //将用户信息放入SecurityContext上下文
        SecurityContextHolder.getContext().setAuthentication(authentication);
        filterChain.doFilter(request, response);
    }

}
